AVR675 Configurable Three Phase Fan  2.0
main.c
Go to the documentation of this file.
00001 /* This file has been prepared for Doxygen automatic documentation generation.*/
00055 #include <avr/io.h>
00056 #include <avr/interrupt.h>
00057 #include <avr/eeprom.h>
00058 
00059 
00060 //*****************************************************************************
00061 // Declarations
00062 //*****************************************************************************
00063 
00064 // Driver stage pin mapping.
00065 #define UL    PB0       // UL
00066 #define UH    PB1       // UH
00067 #define VL    PB2       // VL
00068 #define VH    PB3       // VL
00069 #define WL    PB4       // WL
00070 #define WH    PB5       // WH
00071 
00072 #define EDGE_FALLING 1 // Zero crossing polarity flag value for falling zero crossing.
00073 #define EDGE_RISING  0 // Zero crossing polarity flag value for rinsing zero crossing.
00074 
00075 #define UPPER_DRIVE_MASK      ((1 << UH) | (1 << VH) | (1 << WH))
00076 
00077 #define UPPER_DRIVE_STEP1_CW      (1 << VH) // Drive pattern for commutation step 1, CW rotation.
00078 #define UPPER_DRIVE_STEP2_CW      (1 << UH) // Drive pattern for commutation step 2, CW rotation.
00079 #define UPPER_DRIVE_STEP3_CW      (1 << UH) // Drive pattern for commutation step 3, CW rotation.
00080 #define UPPER_DRIVE_STEP4_CW      (1 << WH) // Drive pattern for commutation step 4, CW rotation.
00081 #define UPPER_DRIVE_STEP5_CW      (1 << WH) // Drive pattern for commutation step 5, CW rotation.
00082 #define UPPER_DRIVE_STEP6_CW      (1 << VH) // Drive pattern for commutation step 6, CW rotation.
00083 
00084 
00085 #define LOWER_DRIVE_STEP1_CW      (1 << WL) // Drive pattern for commutation step 1, CW rotation.
00086 #define LOWER_DRIVE_STEP2_CW      (1 << WL) // Drive pattern for commutation step 2, CW rotation.
00087 #define LOWER_DRIVE_STEP3_CW      (1 << VL) // Drive pattern for commutation step 3, CW rotation.
00088 #define LOWER_DRIVE_STEP4_CW      (1 << VL) // Drive pattern for commutation step 4, CW rotation.
00089 #define LOWER_DRIVE_STEP5_CW      (1 << UL) // Drive pattern for commutation step 5, CW rotation.
00090 #define LOWER_DRIVE_STEP6_CW      (1 << UL) // Drive pattern for commutation step 6, CW rotation.
00091 
00092 // Loop Compensation
00093 #define HALF_LIMIT 0x7FFFu
00094 #define LOOP_SCALING 3u
00095 
00096 // Input command Pin
00097 #define CMD_PIN PA4 // PWM or UART input command
00098 #define CMD_PIN_TEST (PINA & (1<<CMD_PIN)) // Test command pin
00099 #define CMD_PIN_0  (1<<CMD_PIN)  // Test for pin low (inverted circuitry)
00100 #define CMD_PIN_1 0  // Test for pin high (inverted circuitry)
00101 
00102 
00103 // TACH and Alarm Pin
00104 #define TACH_PIN PA0  //PA0
00105 #define TACH_PIN_0  PORTA |= (1<<TACH_PIN)  //inverted for Configurable BLDC Fan Board
00106 #define TACH_PIN_1  PORTA &= ~(1<<TACH_PIN)  //inverted for Configurable BLDC Fan Board
00107 
00108 // Test Pin
00109 #define TEST_PIN  PA3  //PA3
00110 #define TEST_PIN_0  PORTA &= ~(1<<TEST_PIN)
00111 #define TEST_PIN_1  PORTA |= (1<<TEST_PIN)
00112 
00113 // LED Pin
00114 #define LED_PIN  PB6  //PB6
00115 #define LED_PIN_0  PORTB &= ~(1<<LED_PIN)
00116 #define LED_PIN_1  PORTB |= (1<<LED_PIN)
00117 #define LED_PIN_TOGGLE PORTB ^= (1<<LED_PIN)
00118 
00119 // ADC Channels
00120 #define ADC_PRESCALER 4  //divide by 16 (1MHz ADC clock)
00121 
00122 #define ADC_MUX_I       0x22  // ADC2+Bit 5 – ADLAR: ADC Left Adjust Result
00123 #define ADC_MUX_W       0x24  // ADC4+Bit 5 – ADLAR: ADC Left Adjust Result
00124 #define ADC_MUX_U       0x25  // ADC6+Bit 5 – ADLAR: ADC Left Adjust Result
00125 #define ADC_MUX_V       0x26  // ADC5+Bit 5 – ADLAR: ADC Left Adjust Result
00126 
00127 // Variables
00128 #define VARIABLE_TABLE_SIZE  16  // number of bytes in table
00129 
00130 // EEPROM
00131 #define EEPROM_TABLE_SIZE  32  // number of bytes in table
00132 
00133 // EEPROM
00134 #define HEADER_SIZE  64  // number bytes (0xFF values) sent between data
00135 
00136 
00137 //*****************************************************************************
00138 // Tables (RAM)
00139 //*****************************************************************************
00140 
00141 uint8_t  adc_mux_table_forward[6] = 
00142   {
00143         ADC_MUX_V,
00144         ADC_MUX_U,
00145         ADC_MUX_W,
00146         ADC_MUX_V,
00147         ADC_MUX_U,
00148         ADC_MUX_W
00149   };
00150 
00151 
00152 // Table of upper output patterns for forward driving.
00153 uint8_t upper_comm_table_forward[6] = 
00154 {
00155         UPPER_DRIVE_STEP2_CW,
00156         UPPER_DRIVE_STEP1_CW,
00157         UPPER_DRIVE_STEP6_CW,
00158         UPPER_DRIVE_STEP5_CW,
00159         UPPER_DRIVE_STEP4_CW,
00160         UPPER_DRIVE_STEP3_CW
00161 };
00162 
00163 
00164 // Table of lower output patterns for forward driving.
00165 uint8_t lower_comm_table_forward[6] = 
00166 {
00167         LOWER_DRIVE_STEP2_CW,
00168         LOWER_DRIVE_STEP1_CW,
00169         LOWER_DRIVE_STEP6_CW,
00170         LOWER_DRIVE_STEP5_CW,
00171         LOWER_DRIVE_STEP4_CW,
00172         LOWER_DRIVE_STEP3_CW
00173 };
00174 
00175 
00176 // Edge Level ZC for forward driving.
00177 uint8_t zc_table_forward[6] =
00178 {
00179         EDGE_RISING,
00180         EDGE_FALLING,
00181         EDGE_RISING,
00182         EDGE_FALLING,
00183         EDGE_RISING,
00184         EDGE_FALLING 
00185 };
00186 
00187 
00188 //*****************************************************************************
00189 // Global Variables
00190 //*****************************************************************************
00191 
00192 
00193 // Loop Counter
00194 uint8_t pwm_counter = 0;
00195 
00196 uint8_t bit_test = 0;
00197 
00198 // PWM output
00199 uint16_t pwm_value;
00200 
00201 // Commutation and Timer
00202 uint8_t commutation_step = 0;
00203 uint16_t comm_period;
00204 uint16_t comm_period_temp;
00205 uint16_t timer_capture;
00206 uint16_t timer_capture_last;
00207 
00208 // PWM input command
00209 uint16_t pwm_cmd;
00210 uint16_t pwm_cmd_next;
00211 uint8_t pwm_cmd_updated;
00212 uint16_t pwm_cmd_filter;
00213 uint16_t pwm_cmd_filtered;
00214 
00215 // Motor Commutation
00216 // Commutation interrupt state 0 = update comm state, 1 = back EMF sample
00217 uint8_t comm_inter_state; 
00218 
00219 // ADC Samples
00220 uint8_t bemf_sampled;
00221 uint8_t adc_sample;
00222 uint8_t get_bemf;       
00223 
00224 // Back EMF Phase Locked Loop Compensation
00225 uint16_t y0 = 0;             // Current Speed Count * 16
00226 uint16_t y1 = 0;             // Last Speed Count * 16
00227 uint16_t r0 = 0;             // Current Back EMF error voltage 
00228 uint16_t nr0 = 0;            // Positive Compensation * 128
00229 uint16_t r0_temp = 0;        // Current Back EMF error voltage 
00230 uint16_t nr0_temp = 0;       // Positive Compensation * 128
00231 uint16_t y0_min;             // Lower limit
00232 uint16_t y0_max;             // Upper limit
00233 
00234 //Speed Loop Compensation
00235 uint16_t speed_cmd_calc;  // Calculated speed command
00236 uint16_t slope;
00237 uint16_t delta;
00238 uint16_t intercept;
00239 uint16_t s_y0 = 0;       // Speed Loop Count
00240 uint16_t s_y1 = 0;       // Last Speed Loop Count
00241 uint16_t s_r0 = 0;       // Current Speed Loop error voltage
00242 uint16_t s_nr0 = 0;      // Current Speed Loop error voltage (negative)
00243 uint16_t s_y0_min;       // lower limit
00244 uint16_t s_y0_max;       // upper limit
00245 
00246 //Communication Data
00247 uint8_t comm_data;
00248 uint8_t data_toggle;
00249 
00250 //PWM Timer Back EMF Sampling variables
00251 uint8_t adc_sample_state = 0; // 0 = current, 1 = current, 2 = v_bus,
00252         // 3 = Back EMF 
00253 uint8_t bemf_ready = 0;   // 0 = not ready, 1 = ready
00254 uint8_t commutation_step_sampled = 0;
00255 uint16_t neutral_averaging;
00256 uint8_t neutral = 0;
00257 
00258 // Speed Loop counts
00259 uint8_t s_loop_count = 0;
00260 
00261 // Operation mode
00262 uint8_t input_state = 1;    // 0 = PWM input, 1 = UART Data In
00263 uint8_t output_state = 1;   // 0 = Tach output, 1 = UART Data Out
00264 uint8_t control_state = 1;  // 0 = Speed Control, 1 = Open Loop PWM
00265 
00266 // LED
00267 uint16_t led_blink_count = 0;
00268 
00269 
00270 // EEPROM Parameters
00271 uint8_t valid_byte;
00272 uint8_t eeprom_number;
00273 
00274 uint8_t motor_kpv;
00275 uint8_t motor_kiv;
00276 uint8_t motor_max_speed;
00277 uint8_t motor_norm_speed;
00278 uint8_t motor_min_speed;
00279 
00280 // Serial in
00281 uint8_t bit_count_low;
00282 uint8_t bit_position;
00283 uint16_t bit_timeout;
00284 uint16_t byte_timeout;
00285 uint8_t data_in;
00286 
00287 uint8_t motor_off;   // bit 0 = motor off command,
00288         // bit 1 = motor turned off, bit 2 = transfer variables back to EEPROM 
00289 uint8_t pin_test;    //pin test for calibration
00290 
00291 uint8_t count_dir;
00292 
00293 
00294 // Counter for table operations
00295 uint8_t table_counter = 0;
00296 
00297 // Variable and EEPROM table
00298 uint8_t variable_table[VARIABLE_TABLE_SIZE + EEPROM_TABLE_SIZE];
00299 
00300 // Aliases for variables
00301 #define command                 variable_table[0]
00302 
00303 #define speed_cmd               variable_table[1]
00304 #define speed                   variable_table[2]
00305 #define speed_error             variable_table[3]
00306 
00307 #define current_limit           variable_table[4]
00308 #define current                 variable_table[5]
00309 
00310 #define pwm_limit               variable_table[6]
00311 #define pwm                     variable_table[7]
00312 
00313 #define bemf                    variable_table[8]
00314 #define bemf_error              variable_table[9]
00315 
00316 #define v_bus                    variable_table[10]
00317 #define v_motor                  variable_table[11]
00318 
00319 #define osc_cal                 variable_table[12]
00320 #define osc_error               variable_table[13]
00321 
00322 #define data_rxd                variable_table[14]
00323 
00324 #define counter                 variable_table[15]
00325 
00326 // Aliases for EEPROM values
00327 #define enable_voltage          variable_table[0 + VARIABLE_TABLE_SIZE] 
00328 #define osc_cal_adj             variable_table[1 + VARIABLE_TABLE_SIZE] 
00329 #define data_watch              variable_table[2 + VARIABLE_TABLE_SIZE]
00330 #define mode                    variable_table[3 + VARIABLE_TABLE_SIZE]
00331 #define input_cmd               variable_table[4 + VARIABLE_TABLE_SIZE]
00332 
00333 #define speed_count_min         variable_table[5 + VARIABLE_TABLE_SIZE]
00334 #define speed_count_max         variable_table[6 + VARIABLE_TABLE_SIZE]
00335 #define r0_limit                variable_table[7 + VARIABLE_TABLE_SIZE] 
00336 #define kp                      variable_table[8 + VARIABLE_TABLE_SIZE]
00337 #define ki                      variable_table[9 + VARIABLE_TABLE_SIZE]
00338 #define pll_gravity             variable_table[10 + VARIABLE_TABLE_SIZE]
00339 #define pwm_min                 variable_table[11 + VARIABLE_TABLE_SIZE]
00340 #define pwm_max                 variable_table[12 + VARIABLE_TABLE_SIZE]
00341 #define s_loop_rate             variable_table[13 + VARIABLE_TABLE_SIZE]
00342 #define s_r0_limit              variable_table[14 + VARIABLE_TABLE_SIZE]
00343 #define s_kp                    variable_table[15 + VARIABLE_TABLE_SIZE]
00344 #define s_ki                    variable_table[16 + VARIABLE_TABLE_SIZE]
00345 
00346 #define speed_cmd_min           variable_table[17 + VARIABLE_TABLE_SIZE]
00347 #define speed_cmd_max           variable_table[18 + VARIABLE_TABLE_SIZE]
00348 #define speed_scale             variable_table[19 + VARIABLE_TABLE_SIZE]
00349 
00350 #define current_limit_startup   variable_table[20 + VARIABLE_TABLE_SIZE]
00351 #define current_limit_max       variable_table[21 + VARIABLE_TABLE_SIZE]
00352 #define current_limit_slope     variable_table[22 + VARIABLE_TABLE_SIZE]
00353 
00354 #define v_bus_min                variable_table[23 + VARIABLE_TABLE_SIZE]
00355 
00356 #define command_0               variable_table[24 + VARIABLE_TABLE_SIZE]
00357 #define speed_cmd_0             variable_table[25 + VARIABLE_TABLE_SIZE]
00358 #define command_1               variable_table[26 + VARIABLE_TABLE_SIZE]
00359 #define speed_cmd_1             variable_table[27 + VARIABLE_TABLE_SIZE]
00360 #define command_2               variable_table[28 + VARIABLE_TABLE_SIZE]
00361 #define speed_cmd_2             variable_table[29 + VARIABLE_TABLE_SIZE]
00362 #define command_3               variable_table[30 + VARIABLE_TABLE_SIZE]
00363 #define speed_cmd_3             variable_table[31 + VARIABLE_TABLE_SIZE]
00364 
00365 
00366 //*****************************************************************************
00367 // initialize TACH/Alarm PA0 as output low
00368 //***************************************************************************** 
00369 
00378 void intTACH(void)
00379 {
00380         PORTA &= ~(1<<TACH_PIN);   // set PA0 low
00381         DDRA |= (1<<TACH_PIN);     // make PA0 an output 
00382 }
00383 
00384 
00385 //*****************************************************************************
00386 // initialize Test pin
00387 //***************************************************************************** 
00388 
00400 void intTestPin(void)
00401 {
00402         PORTA &= ~(1<<TEST_PIN);
00403         DDRA |= (1<<TEST_PIN);
00404 }
00405 
00406 
00407 //*****************************************************************************
00408 // initialize LED pin
00409 //***************************************************************************** 
00410 
00420 void intLEDPin(void)
00421 {
00422         PORTB &= ~(1<<LED_PIN);
00423         DDRB |= (1<<LED_PIN);
00424 }
00425 
00426 
00427 //*****************************************************************************
00428 // initialize Timer 0 as Normal, 16-bit mode
00429 //***************************************************************************** 
00430 
00445 void intTimer0(void)
00446 {
00447         // Set up Timer/counter0 
00448         TCCR0A = (1<<TCW0);  // Normal, 16-bit mode
00449         TCCR0B = (1<<CS01);  // Clk/8 Prescaler for 2MHz timer clock
00450 }
00451 
00452 
00453 //*****************************************************************************
00454 // initialize PWM on Timer1
00455 //***************************************************************************** 
00456 
00466 void intPWM(void)
00467 {
00468         //Clear on up-counting.
00469         TCCR1A = (1 << COM1A1) | (0 << COM1A0) | (1 << PWM1A);
00470 
00471         //Set WGM to PWM6, dual slope mode.
00472         TCCR1D = (1 << WGM11) | (1 << WGM10);
00473 
00474         // 16MHz/2/19200 = 417 counts, 0 to 416 (pwm + pwm>>1 + pwm>>3 + + pwm>>6)
00475         // (255+127+31+3)
00476         TC1H = 1;               //
00477         OCR1C = 0xA0;   //416 TOPVALUE (pwm + pwm>>1 + pwm>>3 + + pwm>>6)
00478         // (255+127+31+3)
00479         
00480         TCCR1B = (1 << CS10); //Prescaler 16MHz clock /1 = 16MHz
00481         
00482         //Set PWM pins as output.
00483         // (PWM output is still controlled through TCCR1E register.)
00484         DDRB = (1 << UL)|(1 << UH)|(1 << VL)|(1 << VH)|(1 << WL)|(1 << WH);
00485 }
00486 
00487 
00488 //*****************************************************************************
00489 // initialize ADC PA1(ADC1),PA5(ADC4),PA6(ADC5),PA7(ADC6)
00490 //***************************************************************************** 
00491 
00501 void intADC(void)
00502 {
00503         //PA1(ADC1)-DIR,PA5(ADC4)-THR,PA6(ADC5)-IB,PA7(ADC6)-IA,
00504         //PB6(ADC9)-V+,PB7(ADC10)-TEMP
00505 
00506         //ADMUX – ADC Multiplexer Selection Register
00507         //Bits 7:6 – REFS1:REFS0: Voltage Reference Selection Bits 00= Vcc
00508         //Bit 5 – ADLAR: ADC Left Adjust Result
00509         //Bits 4:0 – MUX4:0: Analog Channel and Gain Selection Bits
00510         ADMUX = ADC_MUX_I;
00511 
00512         //ADCSRA – ADC Control and Status Register A
00513         //Bit 7 – ADEN: ADC Enable
00514         //Bit 6 – ADSC: ADC Start Conversion
00515         //Bit 5 – ADATE: ADC Auto Trigger Enable
00516         //Bits 2:0 – ADPS2:0: ADC Prescaler Select Bits
00517         ADCSRA = ((1<<ADEN) | (1<<ADATE) | ADC_PRESCALER);
00518         
00519         //ADCL an ADCH – The ADC Data Register
00520         //read just ADCH for 8 bit values
00521                 
00522         //ADCSRB – ADC Control and Status Register B
00523         //Timer/Counter1 Overflow - ADTS2 = 1, ADTS1 = 1, ADTS0 = 0
00524         ADCSRB = ((1<<ADTS2) | (1<<ADTS1));
00525         
00526         //DIDR0 – Digital Input Disable Register 0
00527         //Bits 7:4,2:0 – ADC6D:ADC0D: ADC6:0 Digital Input Disable
00528         //Bit 3 – AREFD: AREF Digital Input Disable
00529         DIDR0 |= ((1<<ADC2D)|(1<<ADC4D)|(1<<ADC5D)|(1<<ADC6D));
00530         
00531 // ADATE in ADCSRA -  Auto Triggering is enabled by setting
00532 // the ADC Auto Trigger Enable bit
00533 
00534 // ADTS in ADCSRB - The trigger source is selected by setting
00535 // the ADC Trigger Select bits
00536 }
00537 
00538 
00539 
00540 //*****************************************************************************
00541 // Read in EEPROM values
00542 //***************************************************************************** 
00543 
00553 void read_eeprom(void)
00554 {
00555         table_counter = 0;
00556         while (table_counter < EEPROM_TABLE_SIZE)
00557         {
00558                 
00559                 variable_table[VARIABLE_TABLE_SIZE + table_counter]=
00560                         eeprom_read_byte((uint8_t*)(table_counter));
00561                 table_counter++;
00562         }
00563         table_counter = 0;
00564 }
00565 
00566 
00567 //*****************************************************************************
00568 // write EEPROM values
00569 //***************************************************************************** 
00570 
00580 void write_eeprom(void)
00581 {
00582         cli();
00583         table_counter = 0;
00584         while (table_counter < EEPROM_TABLE_SIZE)
00585         {
00586                 eeprom_write_byte ((uint8_t*)(table_counter),
00587                         variable_table[VARIABLE_TABLE_SIZE + table_counter]);
00588                 table_counter++;
00589         }
00590         table_counter = 0;
00591 //      update_limits();
00592         motor_off = 0;
00593         sei();
00594 }
00595 
00596 
00597 //*****************************************************************************
00598 // test oscillator calibration
00599 //***************************************************************************** 
00600 
00608 void test_oscillator(void)
00609 {
00610         cli();
00611         //PC sends stream of 0 bytes at 19200 baud, for a 468.75us period
00612         
00613         OCR0B = 0xFF; 
00614         OCR0A = 0xFF; 
00615         
00616         //Capture timer period 
00617         pin_test = CMD_PIN_TEST;
00618         while (pin_test == CMD_PIN_1)   //wait while pin is high
00619         {
00620                 pin_test = CMD_PIN_TEST;
00621         }
00622         
00623 //      TEST_PIN_0;     
00624         
00625         pin_test = CMD_PIN_TEST;
00626         while (pin_test == CMD_PIN_0)   //wait while pin is low
00627         {
00628                 pin_test = CMD_PIN_TEST;
00629         }
00630 
00631         TEST_PIN_1;
00632 
00633         pin_test = CMD_PIN_TEST;
00634         while (pin_test == CMD_PIN_1)   //wait while pin is high
00635         {
00636                 pin_test = CMD_PIN_TEST;
00637         }
00638 
00639         //Capture timer value
00640         TCNT0H = 0;
00641         TCNT0L = 0;
00642 
00643 //      TEST_PIN_0;     
00644 
00645         pin_test = CMD_PIN_TEST;
00646         while (pin_test == CMD_PIN_0)   //wait while pin is low
00647         {
00648                 pin_test = CMD_PIN_TEST;
00649         }
00650         //Capture timer value again
00651         comm_period = TCNT0L;
00652         comm_period += (TCNT0H<<8);
00653 
00654 //      TEST_PIN_1;     
00655         //At 2us per count period and a period of 468.75us the count should be 234.
00656         osc_error = comm_period + 128 - 833;
00657         motor_off = 0;
00658         
00659 //      TEST_PIN_0;
00660         
00661         sei();
00662 }
00663 
00664 
00665 //*****************************************************************************
00666 // Enable Interrupts
00667 //***************************************************************************** 
00668 
00676 void intInterrupts(void)
00677 {
00678         cli();
00679         //TIMSK – Timer/Counter1 Interrupt Mask Register
00680         //Bit 4 – OCIE0A: Timer/Counter0 Output Compare Match A Interrupt Enable
00681         TIMSK |= (1<<OCIE0A);
00682         //Bit 2 – TOIE1: Timer/Counter1 Overflow Interrupt Enable
00683         TIMSK |= (1<<TOIE1);
00684         //Bit 3 – ADIE: ADC Interrupt Enable
00685         ADCSRA |= (1<<ADIE);   //Bit 3 – ADIE: ADC Interrupt Enable
00686         sei();
00687 }
00688 
00689 
00690 //*****************************************************************************
00691 // ADC Interrupt - Triggered off of TOV1
00692 //***************************************************************************** 
00693 
00704 ISR(ADC_vect)
00705 {
00706         TEST_PIN_1;
00707         if(adc_sample_state == 0 )
00708         {
00709                 current = ADCH;
00710                 ADMUX = adc_mux_table_forward[commutation_step];
00711                 commutation_step_sampled = commutation_step;
00712                 adc_sample_state = 1;
00713                 
00714         }
00715         else
00716         {
00717                 bemf_sampled = ADCH;
00718         
00719                 if (get_bemf)
00720                 {
00721                         
00722                         if (commutation_step_sampled == commutation_step)
00723                         {
00724                                 bemf = bemf_sampled;
00725                                 neutral_averaging = (neutral_averaging - neutral) + bemf; 
00726                                 v_bus = neutral_averaging>>5;
00727                                 neutral = v_bus>>1;
00728                                 if (pwm < 20)
00729                                 {
00730                                         // Below 20 counts sample window is too small
00731                                         v_bus = neutral;
00732                                 }
00733 
00734                                 bemf_ready = 1;
00735                                 // Increasing Back EMF
00736                                 if (zc_table_forward[commutation_step_sampled] == 0)
00737                                 {
00738                                         if (bemf <= neutral)  // Too Fast
00739                                         {
00740                                                 r0_temp = 0;
00741                                                 nr0_temp = neutral - bemf;
00742                                         }
00743                                         else   // Too Slow
00744                                         {
00745                                                 r0_temp = bemf - neutral;
00746                                                 nr0_temp = 0;
00747                                         }
00748                                 }
00749                                 else
00750                                 {
00751                                         if (bemf <= neutral)  // Too Slow
00752                                         {
00753                                                 r0_temp = neutral - bemf;
00754                                                 nr0_temp = 0;
00755                                         }
00756                                         else  // Too Fast
00757                                         {
00758                                                 r0_temp = 0;
00759                                                 nr0_temp = bemf - neutral;
00760                                         }
00761                                 }
00762                         }
00763                         get_bemf = 0;
00764                 }
00765                 
00766                 ADMUX = ADC_MUX_I;
00767                 adc_sample_state = 0;
00768         }       
00769         
00770         TEST_PIN_0;
00771 }
00772 
00773 
00774 //*****************************************************************************
00775 // Timer1 PWM Interrupt - Center of PWM period
00776 //***************************************************************************** 
00777 
00790 ISR(TIMER1_OVF_vect)
00791 {
00792         TEST_PIN_1;
00793         if (CMD_PIN_TEST == CMD_PIN_1)
00794         {
00795                 pwm_cmd_next++;
00796                 if (bit_position > 0)
00797                 {
00798                         byte_timeout=0;
00799                         bit_timeout++;
00800                         if (bit_timeout > 1920) //100ms
00801                         {
00802                                 bit_position = 0;
00803                         }
00804                 }
00805                 else
00806                 {
00807                         bit_timeout = 0;
00808                 }
00809                 
00810                 byte_timeout++;
00811                 if((bit_count_low > 6)&&(bit_count_low < 10)) // 7, 8, or 9 PWM periods
00812                 {
00813                         data_in = 0;
00814                         bit_position++;
00815                         bit_timeout = 0;
00816                 }
00817                 if((bit_count_low > 2)&&(bit_count_low < 6)) // 3, 4, or 5 PWM periods
00818                 {
00819                         data_in = 1;
00820                         bit_position++;
00821                         bit_timeout = 0;
00822                 }
00823                 bit_count_low = 0;
00824         }
00825         else
00826         {
00827                 bit_count_low++;
00828                 if (bit_count_low > 9)
00829                 {
00830                         bit_count_low = 10;
00831                         bit_position = 0;
00832                 }
00833         }       
00834         if (pwm_counter == 0)
00835         {
00836                 pwm_cmd = pwm_cmd_next;
00837                 pwm_cmd_next = 0;
00838                 pwm_cmd_updated = 1;
00839         }
00840         pwm_counter++;
00841 
00842 
00843         if (input_state == 1)
00844         {
00845                 //Serial Data in (sort of) looking for 4 PWMs low = 1 and
00846                 // 8 PWMs low = 0 only when UART receive enabled
00847 
00848                 if (bit_position == 1)
00849                 {
00850                         data_rxd = 0;  //valid start bit
00851                 }
00852                 if ((bit_position > 0)&&(bit_position < 9))
00853                 {
00854                         data_rxd |= data_in<<(bit_position-1);
00855                 }       
00856                 if (bit_position == 8)
00857                 {
00858                         valid_byte++;
00859                         bit_position = 0;  //start over
00860                 }
00861 
00862                 if ( byte_timeout >= 19200)  //29200/19200Hz = 1sec
00863                 {
00864                         valid_byte=0;
00865                         byte_timeout=0;
00866                 }
00867 
00868                 if (valid_byte == 3)
00869                 {
00870                         if (eeprom_number < EEPROM_TABLE_SIZE)
00871                         {
00872                                 variable_table[eeprom_number + VARIABLE_TABLE_SIZE] = data_rxd;
00873                         }
00874                 
00875                         valid_byte=0;
00876                         if ((eeprom_number == 254)&(data_rxd == 254))
00877                         {
00878                                 motor_off = 5;//Motor off command and variables ready for write
00879                         }
00880                         if ((eeprom_number == 255)&(data_rxd == 255))
00881                         {
00882                                 motor_off = 9; // Motor off command and calibrate oscillator
00883                         }                               
00884                 }
00885                 
00886                 if (valid_byte == 1)
00887                 {
00888                         eeprom_number = data_rxd;
00889                         valid_byte++;
00890                 }
00891         }       
00892         else
00893         {
00894                 valid_byte=0;
00895                 byte_timeout=0;
00896         }
00897         
00898         // Software UART Transmit here
00899         if (output_state == 1)
00900         {
00901                 if ((pwm_counter & 0x0F) == 0)
00902                 {
00903                         TACH_PIN_0;  //Start Bit
00904                 }       
00905                 else
00906                 {
00907                         if ((pwm_counter & 0x0F) < 9)
00908                         {
00909                                 if (comm_data & 0x01)   //LSB first
00910                                 {
00911                                         TACH_PIN_1;             // TXD = 1
00912                                 }
00913                                 else
00914                                 {
00915                                         TACH_PIN_0;         // TXD = 0 
00916                                 }
00917 
00918                                 comm_data = comm_data>>1;
00919                         }
00920                         else
00921                         {
00922                                 TACH_PIN_1;
00923                         }
00924                 }
00925         }
00926         TEST_PIN_0;
00927 }
00928 
00929 
00930 //*****************************************************************************
00931 // Interrupt Timer0 
00932 //***************************************************************************** 
00933 
00950 ISR(TIMER0_COMPA_vect)
00951 {
00952         TEST_PIN_1;
00953         if (comm_inter_state == 1) // back EMF sampling
00954         {
00955                 get_bemf = 1;
00956                 comm_inter_state = 0; // Update Commutation on next interrupt
00957         }
00958 
00959         else  // update commutation state 
00960         {
00961                 commutation_step++;
00962                 if (commutation_step>=6)
00963                 {
00964                         commutation_step=0;
00965                 }
00966                 // Update commutation state
00967                 TCCR1E = lower_comm_table_forward[commutation_step];
00968                 PORTB &=  ~(UPPER_DRIVE_MASK);
00969                 PORTB |= upper_comm_table_forward[commutation_step];
00970                 
00971                 if (output_state == 0) //Only update on proper commutation state edge
00972                 {
00973                         if (commutation_step == 0)
00974                         {
00975                                 TACH_PIN_0;
00976                         }
00977                         if (commutation_step == 3)
00978                         {
00979                                 TACH_PIN_1;
00980                         }
00981                 } 
00982                 comm_inter_state = 1; // Back EMF sample on next interrupt
00983         }
00984 
00985         // Update Timer Compare Value
00986         timer_capture = timer_capture_last + comm_period;
00987         OCR0B = (timer_capture >> 8); 
00988         OCR0A = timer_capture; 
00989         timer_capture_last = timer_capture;
00990 
00991         TEST_PIN_0;
00992 
00993 }
00994 
00995 
00996 //*****************************************************************************
00997 // Main
00998 //*****************************************************************************
00999 
01018 int main(void)
01019 {
01020         intPWM();               // Initialize timer1 as PWM6 mode center aligned
01021         intTimer0();            // Initialize timer0 for commutation timing
01022         intTACH();              // Initialize I/O pin as tachometer out
01023         intTestPin();           // Initialize I/O pin as test pin
01024         intLEDPin();            // Initialize I/O pin as LED indicator
01025         intADC();               // Initialize ADC
01026         read_eeprom();          // Read the EEPROM contents once on power up
01027         intInterrupts();        // Enable interrupts
01028         
01029         osc_cal = OSCCAL;       // Read the factory calibration once on power up
01030 
01031     while(1)
01032     {
01033                 
01034                 led_blink_count++;
01035                 if (led_blink_count >= comm_period_temp)
01036                 {
01037                         LED_PIN_TOGGLE;
01038                         led_blink_count = 0;
01039                 }
01040 
01041                 //Recalculated limits in case they have changed from
01042                 // Fan Configuration Utility
01043                 y0_min = ((speed_count_min<<LOOP_SCALING) + HALF_LIMIT);
01044                 y0_max = ((speed_count_max<<LOOP_SCALING) + HALF_LIMIT);
01045                 s_y0_min = ((pwm_min<<LOOP_SCALING) + HALF_LIMIT);
01046                 s_y0_max = ((pwm_max<<LOOP_SCALING) + HALF_LIMIT);
01047                         
01048                 // Compare DC input voltage (V_bus) with enable_voltage,
01049                 // below threshold use defaults
01050                 if (v_bus <= enable_voltage)
01051                 {
01052                         input_state = 1;      //0 = pwm input, 1 = UART Data In
01053                         output_state = 1;     //0 = Tach output, 1 = UART Data Out
01054                         control_state = 1;    //0 = Speed Control, 1 = Open Loop PWM
01055                         OSCCAL = osc_cal;
01056                 }
01057                 else
01058                 {
01059                         input_state = (mode & 0x01);       //0 = PWM input,
01060                         // 1 = UART Data In
01061                         output_state = (mode & 0x02)>>1;   //0 = Tach output,
01062                         // 1 = UART Data Out
01063                         control_state = (mode & 0x04)>>2;  //0 = Speed Control,
01064                         // 1 = Open Loop PWM
01065                         if (osc_cal_adj < 33)
01066                         {
01067                                 OSCCAL = osc_cal + osc_cal_adj - 16;
01068                         }
01069                         else
01070                         {
01071                                 OSCCAL = osc_cal;
01072                         }       
01073                 }
01074                 
01075                 // Wait here for 16 PWM periods to pass -
01076                 // Timing for control loop 19200Hz/16 = 1200Hz (833us)
01077                 cli();
01078                 bit_test = (pwm_counter & 0x0F);
01079                 sei();
01080                 while(bit_test != 0x0F)
01081                 {
01082                         cli();
01083                         bit_test = (pwm_counter & 0x0F);
01084                         sei();
01085                 }
01086                 cli();
01087                 bit_test = (pwm_counter & 0x0F);
01088                 sei();
01089                 while(bit_test > 0)
01090                 {               
01091                         cli();
01092                         bit_test = (pwm_counter & 0x0F);
01093                         sei();
01094                 }
01095 
01096                 // Calculate Motor Voltage
01097                 v_motor = (v_bus*pwm)>>8;
01098 
01099                 // Write EEPROM function here. Non-reentrant so must disable interrupts 
01100                 if (motor_off == 7)   // bit 0 = motor off command,
01101                 // bit 1 = motor turned off, bit 2 = transfer variables back to EEPROM,
01102                 // bit 3 = Cal Oscillator
01103                 {
01104                                 write_eeprom();
01105                 }
01106                 if (motor_off == 11)   // bit 0 = motor off command,
01107                 // bit 1 = motor turned off,
01108                 // bit 2 = transfer variables back to EEPROM bit 3 = Cal Oscillator 
01109                 {
01110                                 test_oscillator();
01111                 }
01112 
01113                 // Serial Data Selection
01114                 if (data_toggle)
01115                 {
01116                         if (table_counter < (VARIABLE_TABLE_SIZE + EEPROM_TABLE_SIZE))
01117                         {
01118                                 comm_data = variable_table[table_counter];
01119                         }
01120                         else
01121                         {
01122                                 if (table_counter == (VARIABLE_TABLE_SIZE + EEPROM_TABLE_SIZE))
01123                                 {
01124                                         comm_data = 0;      // 0 at end of data
01125                                 }
01126                                 else
01127                                 {
01128                                         comm_data = 255;    // The rest of the data is 255s
01129                                 }
01130                                 
01131                         }
01132                         table_counter++;
01133                         if (table_counter > (HEADER_SIZE + VARIABLE_TABLE_SIZE +
01134                                  EEPROM_TABLE_SIZE + 1))
01135                         {               
01136                                 table_counter = 0;
01137                                 comm_data = 0;    // 0 at beginning of data
01138                                 
01139                         }
01140                         data_toggle = 0;
01141                 }
01142                 else
01143                 {
01144                         
01145                         if (count_dir == 0)
01146                         {
01147                                 counter++;
01148                                 if (counter>254)
01149                                 {
01150                                         count_dir = 1;
01151                                 }
01152                         }
01153                         else
01154                         {
01155                                 counter--;
01156                                 if (counter<1)
01157                                 {
01158                                         count_dir = 0;
01159                                 }
01160                         }
01161                         
01162                         comm_data = variable_table[data_watch];
01163                         if (comm_data > 254)
01164                         {
01165                                 comm_data = 254; // Clip data at 254
01166                         }
01167                         data_toggle = 1;
01168                 }
01169 
01170 
01171                 // PWM input (Speed command) averaging filter
01172                 if (pwm_cmd_updated == 1)
01173                 {
01174                         pwm_cmd_updated = 0;
01175                         pwm_cmd_filter = (pwm_cmd_filter - pwm_cmd_filtered) + pwm_cmd;
01176                         pwm_cmd_filtered = pwm_cmd_filter>>6;
01177                         if (pwm_cmd_filtered > 255)
01178                         {
01179                                 pwm_cmd_filtered = 255;
01180                         }
01181                 }
01182 
01183 
01184                 // Check to see where command comes from either
01185                 // Fan Configuration Utility of PWM input (Speed command)
01186                 if (input_state == 1)
01187                 {
01188                         command = input_cmd;
01189                 }
01190                 else
01191                 {
01192                         command = pwm_cmd_filtered;
01193                 }
01194 
01195 
01196                 // Back EMF Sensing PLL Update
01197                 if (bemf_ready == 1)
01198                 {
01199 
01200                         cli();
01201                         bemf_ready = 0;
01202                         r0=r0_temp;
01203                         nr0=nr0_temp;
01204                         sei();
01205                 
01206                         // Back EMF sensing PLL PI regulator
01207                         if(r0>r0_limit)
01208                         {
01209                                 r0=r0_limit;
01210                         }
01211                         if(nr0>r0_limit)
01212                         {
01213                                 nr0=r0_limit;
01214                         }               
01215 
01216                         nr0 += pll_gravity;
01217                         
01218                         bemf_error = 128 + r0 - nr0;
01219                         
01220                         y1 += ((r0*ki)>>8);    // ki
01221                         y1 -= ((nr0*ki)>>8);   // ki
01222                 
01223                         if (y1 < y0_min)
01224                         {
01225                                 y1 = y0_min; 
01226                         }
01227                         if (y1 > y0_max)
01228                         {
01229                                 y1 = y0_min;      // Restart PLL
01230                         }
01231                         
01232                         y0 = y1 + ((r0*kp)>>8) - ((nr0*kp)>>8);   // kp
01233                         
01234                         if (y0 < y0_min)
01235                         {
01236                                 y0 = y0_min; 
01237                         }
01238                         if (y0 > y0_max)
01239                         {
01240                                 y0 = y0_min;    // Restart PLL
01241                         }                       
01242                         
01243                         if (speed_cmd < speed_cmd_min)
01244                         {
01245                                 y1 = y0_min;    // Restart PLL
01246                         }
01247                 
01248                         speed = (y0 - HALF_LIMIT) >> LOOP_SCALING;
01249 
01250                         comm_period_temp = (0xFFFF/speed)>>speed_scale;
01251 
01252                         cli();
01253                         comm_period = comm_period_temp;
01254                         sei();
01255                 }
01256         
01257 
01258                 // Speed Control Loop Update
01259                 s_loop_count++;
01260                 if (s_loop_count >= s_loop_rate)
01261                 {
01262                         s_loop_count = 0;
01263                         // Speed command Mapping 
01264                         
01265                         if (command > command_3)
01266                         {
01267                                 slope = 255 - speed_cmd_3;
01268                                 delta = command - command_3;
01269                                 intercept = speed_cmd_3;
01270                         }
01271                         else
01272                         {
01273                                 if (command > command_2)
01274                                 {
01275                                         slope = speed_cmd_3 - speed_cmd_2;
01276                                         delta = command - command_2;
01277                                         intercept = speed_cmd_2;        
01278                                 }
01279                                 else
01280                                 {
01281                                         if (command > command_1)
01282                                         {
01283                                                 slope = speed_cmd_2 - speed_cmd_1;
01284                                                 delta = command - command_1;
01285                                                 intercept = speed_cmd_1;
01286                                         }
01287                                         else
01288                                         {
01289                                                 if (command > command_0)
01290                                                 {
01291                                                         slope = speed_cmd_1 - speed_cmd_0;
01292                                                         delta = command - command_0;
01293                                                         intercept = speed_cmd_0;
01294                                                 }
01295                                                 else
01296                                                 {
01297                                                         slope = 0;
01298                                                         delta = 0;
01299                                                         intercept = 0;
01300                                                 }
01301                                         }
01302                                 }
01303                         }
01304                         
01305                         speed_cmd_calc = ((slope*delta)/255) + intercept;
01306 
01307 //                      speed_cmd = command; //Linear Mapping for testing purposes
01308                                 
01309                         if (speed_cmd_calc > speed_cmd_max)
01310                         {
01311                                 speed_cmd_calc = speed_cmd_max;
01312                         }
01313                         
01314                         if (speed_cmd_calc < speed_cmd_min)
01315                         {
01316                                 speed_cmd_calc = speed_cmd_min;
01317                         }
01318                         
01319                         speed_cmd = speed_cmd_calc;
01320                         
01321                         // Speed Control PI regulator
01322                         if (speed > speed_cmd)
01323                         {
01324                                 s_nr0 = speed - speed_cmd;
01325                                 s_r0 = 0;
01326                         }
01327                         else
01328                         {
01329                                 s_r0 = speed_cmd - speed;
01330                                 s_nr0 = 0; 
01331                         }
01332 
01333                         if(s_nr0>s_r0_limit)
01334                         {
01335                                 s_nr0=s_r0_limit;
01336                         }
01337                         if(s_r0>s_r0_limit)
01338                         {
01339                                 s_r0=s_r0_limit;
01340                         }               
01341 
01342 
01343                         speed_error = 128 - s_r0 - s_nr0;
01344 
01345                         s_y1 += ((s_r0*s_ki)>>6);   //s_ki
01346                         s_y1 -= ((s_nr0*s_ki)>>6);  //s_ki
01347                         
01348                         if (s_y1 < s_y0_min)
01349                         {
01350                                 s_y1 = s_y0_min; 
01351                         }
01352                         if (s_y1 > s_y0_max)
01353                         {
01354                                 s_y1 = s_y0_max;
01355                         }
01356                         
01357                         s_y0 = s_y1 + ((s_r0*s_kp)>>6) - ((s_nr0*s_kp)>>6); //s_kp 
01358                         
01359                         if (s_y0 < s_y0_min)
01360                         {
01361                                 s_y0 = s_y0_min; 
01362                         }
01363                         if (s_y0 > s_y0_max)
01364                         {
01365                                 s_y0 = s_y0_max;
01366                         }                       
01367         
01368                         pwm = (s_y0 - HALF_LIMIT) >> LOOP_SCALING;
01369                 }
01370 
01371                 // Open Loop PWM or Speed Control
01372                 if (control_state == 1)  // Direct PWM command for testing purposes
01373                 {
01374                         
01375                         if (command>pwm_max)
01376                         {
01377                                 pwm = pwm_max;
01378                         }
01379                         else
01380                         {
01381                                 pwm = command;
01382                                 if (pwm < pwm_min)
01383                                 {
01384                                         pwm = pwm_min;
01385                                 }
01386                         }
01387                 }                       
01388 
01389                 // Current limiting
01390                 if (speed < speed_cmd_min )
01391                 {       
01392                         // Lower Current limit gives better startup performance
01393                         current_limit = current_limit_startup;
01394                 }
01395                 else   //Higher current limit for high speed operation
01396                 {
01397                         current_limit = current_limit_startup + 
01398                                 ((((speed - speed_cmd_min)*current_limit_slope)>>8));
01399                         if (current_limit > current_limit_max)
01400                         {
01401                                 // upper current limit for high power operation
01402                                 current_limit = current_limit_max;
01403                         }
01404                 }
01405                 
01406                 // Folds back PWM when exceeding current limit
01407                 if (current > current_limit)
01408                 {
01409 //                      TEST_PIN_1;
01410                         if (pwm_limit > 1)
01411                         {
01412                                 pwm_limit--;
01413                         }
01414                 }
01415                 else
01416                 {
01417                         if (pwm_limit < pwm)
01418                         {
01419                                 pwm_limit++;
01420                         }
01421                 }       
01422 
01423                 if (pwm > pwm_limit)
01424                 {
01425                         pwm = pwm_limit;
01426                 }
01427 
01428                 // Minimum DC Bus Voltage before enabling
01429                 // back EMF sensing and speed control
01430                 if (v_bus < v_bus_min)
01431                 {
01432                         pwm = pwm_min;
01433                         s_y1 = s_y0_min;   // Reset Integrator
01434                         s_y0 = 0;          // PWM off
01435                         y1 = y0_min;       // Restart PLL
01436                 }
01437                 
01438                 // Motor Off function for updating EEPROM 
01439                 if (motor_off == 0)
01440                 {
01441                         // 16MHz/2/19200 = 417 counts, 0 to 416 
01442                         // (pwm + pwm>>1 + pwm>>3 + + pwm>>6) (255+127+31+3)
01443                         pwm_value = pwm + (pwm>>1) + (pwm>>3) + (pwm>>6);
01444                         cli();
01445                         TC1H = (pwm_value >> 8); 
01446                         OCR1A = pwm_value;
01447                         sei();
01448                 }
01449                 else
01450                 {
01451                         cli();
01452                         TC1H = 0; 
01453                         OCR1A = 0;
01454                         motor_off |= 2;  // Motor PWM at zero
01455                         sei();
01456                         //pwm = pwm_min;
01457                         s_y1 = s_y0_min;   // Reset Integrator
01458                         s_y0 = 0;          // PWM off
01459                         y1 = y0_min;       // Restart PLL
01460                 }
01461 
01462     }
01463 }